﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Petra.Gis.DataServices.WKT
{
  public class RegexGeometry : IEnumerable<RegexGeometry>
  {

    public enum NodeType
    {
      Undefined = 0,
      Collection = 2,
      Coordlist = 3
    }

    private int _startIndex;
    private int _endIndex;
    private string _groupName;
    private NodeType _nodeType;
    private List<RegexGeometry> _items;
    private RegexGeometry _parent;
    private RegexGeometryParser _rgp;


    //root node constructor
    internal RegexGeometry(RegexGeometryParser rgp)
    {
      //root node constructor
      //_nodeType = NodeType.Root;
      _rgp = rgp;
      _groupName = "geometry";
      _startIndex = 0;
      _endIndex = 1;
      Initialize(null, 1);
    }

    //child node constructor
    internal RegexGeometry(RegexGeometry parent, string groupName, int currentCollectionLevel, int startIndex, int endIndex)
    {
      //_nodeType = NodeType.Undefined;
      _groupName = groupName;
      _startIndex = startIndex;
      _endIndex = endIndex;
      _rgp = parent.parser;
      Initialize(parent, currentCollectionLevel);
    }




    private void Initialize(RegexGeometry parent, int currentCollectionLevel)
    {
      _parent = parent;

      int noOfItems = getTotalNumOfGeometries(currentCollectionLevel);


      if (noOfItems == 0) //collection not found, treat as coordlist
      {
        prepareCoordList();
      }
      else
      {
        prepareCollection(currentCollectionLevel);
      }
    }


    public int startIndex
    {
      get{return _startIndex;}
    }

    public int endIndex
    {
      get{return _endIndex;}
    }

    public string groupName
    {
      get{return _groupName;}
    }

    public NodeType nodeType
    {
      get { return _nodeType; }
    }

    public RegexGeometryParser parser
    {
      get { return _rgp; }
    }


    private void prepareCoordList()
    {

      this._nodeType = NodeType.Coordlist;

      if (_parent == null) //root node is coordlist
      {
        _startIndex = _rgp.getStartByCapture("coordlist", _rgp.regexMatch.Groups["geometry"].Captures[0]);
        _endIndex = _rgp.getEndByCapture("coordlist", _rgp.regexMatch.Groups["geometry"].Captures[1]);
      }
      else
      {
        _startIndex = _rgp.getStartByCapture("coordlist", _rgp.regexMatch.Groups[_groupName].Captures[_startIndex]);
        _endIndex = _rgp.getEndByCapture("coordlist", _rgp.regexMatch.Groups[_groupName].Captures[_endIndex]);
      }

      //if (_groupName == null)
      //rename group to coordlist
      _groupName = "coordlist";

    }





    private void prepareCollection(int currentCollectionLevel)
    {
      //if (_groupName == null)
      //  _groupName = "geometry" + currentCollectionLevel.ToString();

      _nodeType = NodeType.Collection;

      RegexGeometry tmpRg;
      int startPos;
      int endPos;

      //setup position for current node
      if (_parent == null) //root node is coordlist
      {
        startPos = _rgp.getStartByCapture("geometry" + currentCollectionLevel.ToString(), _rgp.regexMatch.Groups["geometry"].Captures[0]);
        endPos = _rgp.getEndByCapture("geometry" + currentCollectionLevel.ToString(), _rgp.regexMatch.Groups["geometry"].Captures[1]);
      }
      else
      {
        startPos = _rgp.getStartByCapture("geometry" + currentCollectionLevel.ToString(), _rgp.regexMatch.Groups[_groupName].Captures[_startIndex]);
        endPos = _rgp.getEndByCapture("geometry" + currentCollectionLevel.ToString(), _rgp.regexMatch.Groups[_groupName].Captures[_endIndex]);
      }

      //validate if start and end gives pair
      //if ((endPos - startPos + 1) % 2 != 0)
      //  throw new ArgumentException("invalid wkt representation","wktstring");

      //create subnodes...
      _items = new List<RegexGeometry>();
      while (startPos < endPos)
      {
        tmpRg = new RegexGeometry(this, "geometry" + currentCollectionLevel.ToString(), currentCollectionLevel + 1, startPos, startPos + 1);
        _items.Add(tmpRg);
        startPos += 2; //tokens gives always pair
      }
    }
    




    //IEnumerator
    //public IEnumerator<T> GetEnumerator()
    public IEnumerator<RegexGeometry> GetEnumerator()
    {
      //while (_items.)
      foreach(RegexGeometry rg in _items)
      {
        yield return rg;
      }
    }

      IEnumerator IEnumerable.GetEnumerator()
      {
        return GetEnumerator();
      }

      public RegexGeometry this[int index]
      {
        get { return _items[index]; }
      }




      private int getTotalNumOfGeometries(int currentCollectionLevel)
      {
        int noOfItems;
        //test for collections...
        try
        {
          CaptureCollection cc = _rgp.regexMatch.Groups["geometry" + currentCollectionLevel.ToString()].Captures;
          noOfItems = cc.Count;
        }
        catch { noOfItems = 0; }

        return noOfItems;
      }

    }

  }
